/*
 * @Title: HttpClientFluentStu.java
 * @Package
 * @Description: TODO
 * @author tbc
 * @date 2016年7月3日 上午5:04:26
 * @version
 */
package tbg.http;

import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.google.gson.Gson;
import org.apache.http.*;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import pub.tbc.toolkit.DateFormats;
import pub.tbc.toolkit.Sleeps;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 福田
 * http: http://amdms.foton.com.cn
 * user: dmsadmin@foton.com.cn
 * pass: 8312wang
 */
public class FTRest {

    private static volatile int n = 1;
    private static AtomicInteger atomicRequestCount = new AtomicInteger(1);
    private static int THREAD_POOL_SIZE;
    private static String COOKIE;

    static {
        THREAD_POOL_SIZE = 24;
        COOKIE = "username=dmsadmin@foton.com.cn; style=blue; username=dmsadmin@foton.com.cn; JSESSIONID=vhX5ZnxMvDhGvJPQGTyDLXX0kDgp2G3Gl0S4YGjnyGB9xPbJlbqh!-1644893124";
    }

    private static File getVinFile() {
        return new File("c:\\Users\\tbc\\Desktop\\vin.txt");
    }

    private static File getOutputFile() {
        return new File("c:\\Users\\tbc\\Deskt op\\amdms.xlsx");
    }

    private static String getCookie() {
        return COOKIE;
    }

    public static void main(String[] args) throws IOException {
        long startTime = System.currentTimeMillis();
        System.out.println("程序启动，开始计时，当前时间： " + DateFormats.format(startTime));

        System.out.println("获取COOKIE，以及系统登陆...");
        login();

        System.out.println("获取VIN...");
        List<String> vinS = Files.readLines(getVinFile(), Charset.forName("UTF-8"));
        System.out.println("vin 数量：" + vinS.size());

        System.out.println("开始请求数据...");
        List<Map<String, Object>> outList = request2(vinS);

        System.out.println("请求全部完成，正在输出到excel文件");
        excel(outList, getOutputFile());

        long endTime = System.currentTimeMillis();
        System.out.println("全部工作完成,共耗时： " + (endTime - startTime));
        System.out.println("正在退出...");
        Sleeps.seconds(2);

    }

    private static void login() throws IOException {
        System.out.println("请求首页，获取Set-Cookie...");
        Header[] setCookie = getInitRequest("http://amdms.foton.com.cn").execute().returnResponse().getHeaders("Set-Cookie");
        COOKIE = setCookie[0].getValue();
        HeaderElement[] elements = setCookie[0].getElements();

        Optional<HeaderElement> cookieElement = Arrays.stream(elements)
                .filter(element -> element.getName().equalsIgnoreCase("JSESSIONID"))
                .findFirst();

        HeaderElement headerElement = cookieElement.get();

        String JSESSIONID = headerElement.getValue();
        // 设置COOKIE
        COOKIE = "username=dmsadmin@foton.com.cn; style=blue; username=dmsadmin@foton.com.cn;"
                + "JSESSIONID=" + JSESSIONID;

        // 登陆请求
        Request request = getInitRequest("http://amdms.foton.com.cn/gensoft/Login.html");
        String form = "tmUser.username=dmsadmin%40foton.com.cn&" +
                "tmUser.password=aeb1b5c4493b05f2cdec98ece403cb9f&" +
                "tmUser.fcmPassword=895acd6deacdb070b7a0331c10bb493b6dca560e";
        HttpResponse loginResponse = request.bodyString(form, ContentType.create("application/x-www-form-urlencoded", Consts.UTF_8))
                .addHeader("Cookie", COOKIE)
                .execute()
                .returnResponse();
        System.out.println("登陆请求响应码： " + loginResponse.getStatusLine().getStatusCode());

    }


    private static String getBody() {
        return "queryData.start=0" +
                "&queryData.limit=10" +
                "&queryData.vehicleStatus=" +
                "&queryData.orgaId=" +
                "&queryData.stockDaysEnd=" +
                "&queryData.stockDays=" +
                "&queryData.productGroup=" +
                "&queryData.dealerId=" +
                "&queryData.vin=";
    }

    private static List<Map<String, Object>> request(List<String> vinS) {
        String body = getBody();
        String cookie = getCookie();

        List<Map<String, Object>> outList = Lists.newArrayList();

        vinS.forEach(it -> {
            System.out.println("发送第" + n++ + "次请求, time = " + getNowTime());
            Request request = getInitRequest(null);
            String resultjson = null;
            try {
                resultjson = request.addHeader("Cookie", cookie)
                        .bodyString(body + it, ContentType.APPLICATION_FORM_URLENCODED)
                        .execute()
                        .returnContent()
                        .asString();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("->请求完成, time = " + getNowTime());

            Result result = new Gson().fromJson(resultjson, Result.class);
            List<Map<String, Object>> list = result.getList();
            Map<String, Object> row = list.get(0);
            outList.add(row);
            // 打印看看
            String vin = row.get("vin").toString();
            String productGroupName = row.get("productGroupName").toString();
            String znbbm = row.get("znbbm").toString();

            System.out.println("vin: " + vin);
            System.out.println("产品组: " + productGroupName);
            System.out.println("内部编号: " + znbbm);
        });


        return outList;
    }

    /**
     * 多线程请求
     *
     * @param vinS vin
     * @return data
     */
    private static List<Map<String, Object>> request2(List<String> vinS) {
        String body = getBody();
        String cookie = getCookie();

        // 多线程请求，用同步容器，存放请求结果
        List<Map<String, Object>> outList = Collections.synchronizedList(new ArrayList<>());
        // 阻塞队列，存vin, ArrayBlockingQueue<String>更好些，读取更快
//        BlockingQueue<String> queue = new LinkedBlockingQueue<>(vinS);

        ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        CountDownLatch latch = new CountDownLatch(vinS.size());

        vinS.forEach(vin -> {
            threadPool.execute(() -> {
                System.out.println("发送第" + atomicRequestCount.getAndAdd(1) + "次请求, time = " + getNowTime());
                Request request = getInitRequest(null);
                String resultjson = null;
                try {
                    resultjson = request.addHeader("Cookie", cookie)
//                            .bodyString(body + queue.take(), ContentType.APPLICATION_FORM_URLENCODED)
                            .bodyString(body + vin, ContentType.APPLICATION_FORM_URLENCODED)
                            .execute()
                            .returnContent()
                            .asString();
                } catch (Exception e) {
                    e.printStackTrace();
                }
//                System.out.println("->请求完成, time = " + getNowTime());
                System.out.println(String.format("-> 第 %d 次请求完成，time = %s", atomicRequestCount.get(), getNowTime()));

                Result result = null;
                try {
                    result = new Gson().fromJson(resultjson, Result.class);
                } catch (Exception e) {
                    System.out.println("请求错误...");
//                    Sleeps.seconds(1);
                    threadPool.shutdownNow();
                    System.exit(0);
                }
                List<Map<String, Object>> list = result.getList();
                Map<String, Object> row = list.get(0);
                outList.add(row);
                // 打印看看
                String _vin = row.get("vin").toString();
                String productGroupName = row.get("productGroupName").toString();
                String znbbm = row.get("znbbm").toString();

                System.out.println("vin: " + _vin);
                System.out.println("产品组: " + productGroupName);
                System.out.println("内部编号: " + znbbm);
                latch.countDown();
            });
        });
        threadPool.shutdown();

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return outList;
    }

    private static void excel(List<Map<String, Object>> dataList, File outFile) throws IOException {
        XSSFWorkbook book = new XSSFWorkbook();
        XSSFSheet sheet = book.createSheet("sheet1");

        for (int i = 0; i < dataList.size(); i++) {
            Map<String, Object> _row = dataList.get(i);
            XSSFRow row = sheet.createRow(i);

            XSSFCell c1 = row.createCell(0);
            c1.setCellValue(_row.get("vin").toString());
            XSSFCell c2 = row.createCell(1);
            c2.setCellValue(_row.get("productGroupName").toString());
            XSSFCell c3 = row.createCell(2);
            c3.setCellValue(_row.get("znbbm").toString());

        }
        OutputStream os = new FileOutputStream(outFile);
        book.write(os);
        os.flush();
        os.close();
    }

    private static void write(XSSFWorkbook book, File outFile) throws IOException {
        OutputStream os = new FileOutputStream(outFile);
        book.write(os);
        os.flush();
        os.close();
    }

    private static Request getInitRequest(String url) {
        url = url == null ? "http://amdms.foton.com.cn/vehivle/dealerVehicleQueryList.html" : url;
        return Request.Post(url)//
                .addHeader("Host", "amdms.foton.com.cn")//
                .addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:42.0) Gecko/20100101 Firefox/42.0")//
                .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
                .addHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")
                .addHeader("addAccept-Encoding", "gzip, deflate")
                .addHeader("X-Requested-With", "XMLHttpRequest")
                .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                .addHeader("Referer", "http://amdms.foton.com.cn/vehivle/goFactoryVehivleQuery.html?time=" + System.currentTimeMillis())
                .addHeader("Connection", "keep-alive")
                .addHeader("Pragma", "no-cache")
                .addHeader("Cache-Control", "no-cache")
                .version(HttpVersion.HTTP_1_1);
    }

    private static String getNowTime() {
        return LocalTime.now().toString();
    }
}